/*
 * Copyright (c) 2008, Xiong Yingfei, the University of Tokyo
 * All rights reserved.
 */
package ac.jp.u_tokyo.SyncLib.language3;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import sun.awt.VariableGridLayout;
import sun.security.action.GetLongAction;

import ac.jp.u_tokyo.SyncLib.language.Const;
import ac.jp.u_tokyo.SyncLib.language.ConstRef;
import ac.jp.u_tokyo.SyncLib.language.EvaluationFailedException;
import ac.jp.u_tokyo.SyncLib.language.GraphCombinatorBody;
import ac.jp.u_tokyo.SyncLib.language.NativeSyncBody;
import ac.jp.u_tokyo.SyncLib.language.SyncBody;

public class SetMemberExpr extends FixedParaSyncConstructBase
{

	
	public static abstract class RightPart extends LineConstruct{
		public RightPart(int line)
		{
			super(line);
		}
		public abstract Var getConnectionVar(Collection<String> genericParas) throws EvaluationFailedException;
		public abstract void addBody(GraphCombinatorBody body, Collection<String> genericParas, Var leftVar) throws EvaluationFailedException;
		public abstract Collection<Var> getVarUsed(Collection<String> genericParas)
		throws EvaluationFailedException;
	}
	
	public static class TestEqualRightPart  extends RightPart{
		public TestEqualRightPart(int line, Part right)
		{
			super(line);
			_right = right;
		}

		Part _right;

		@Override
		public void addBody(GraphCombinatorBody body,
				Collection<String> genericParas, Var leftVar)
				throws EvaluationFailedException
		{
			Var rightVar;
			if (_right.getConnectionVar(genericParas) == null) {
				rightVar = Helper.createNewVar(body);
			}
			else
				rightVar = _right.getConnectionVar(genericParas);
			
			_right.addBody(body, genericParas, rightVar);
			
			List<Var> paras = new LinkedList<Var>();
			paras.add(leftVar);
			paras.add(rightVar);
			body.addConnection(NativeSyncFactory.createEqual2(getLine()), Helper.higherVar2LowerVar(paras));
		}

		@Override
		public Var getConnectionVar(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return _right.getConnectionVar(genericParas);
		}

		@Override
		public Collection<Var> getVarUsed(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return _right.getVarUsed(genericParas);
		}
		
	}

	public static class NotEqualRightPart  extends RightPart{
		public NotEqualRightPart(int line, Part right)
		{
			super(line);
			_right = right;
		}

		Part _right;

		@Override
		public void addBody(GraphCombinatorBody body,
				Collection<String> genericParas, Var leftVar)
				throws EvaluationFailedException
		{
			Var rightVar;
			if (_right.getConnectionVar(genericParas) == null) {
				rightVar = Helper.createNewVar(body);
			}
			else
				rightVar = _right.getConnectionVar(genericParas);
			
			_right.addBody(body, genericParas, rightVar);
			
			List<Var> paras = new LinkedList<Var>();
			paras.add(leftVar);
			paras.add(rightVar);
			body.addConnection(NativeSyncFactory.createNotEqual2(getLine()), Helper.higherVar2LowerVar(paras));
		}


		@Override
		public Var getConnectionVar(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return _right.getConnectionVar(genericParas);
		}

		@Override
		public Collection<Var> getVarUsed(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return _right.getVarUsed(genericParas);
		}
		
	}
	
	public static class TestEqualConstRightPart extends RightPart{
		Const _const;

		public TestEqualConstRightPart(int line, Const constValue)
		{
			super(line);
			_const = constValue;
		}

		@Override
		public void addBody(GraphCombinatorBody body,
				Collection<String> genericParas, Var leftVar)
				throws EvaluationFailedException
		{
			List<Var> paras = new LinkedList<Var>();
			paras.add(leftVar);
			body.addConnection(NativeSyncFactory.createTestEqual(_const, getLine()), Helper.higherVar2LowerVar(paras));
		}

		@Override
		public Var getConnectionVar(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return null;
		}

		@Override
		public Collection<Var> getVarUsed(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			Collection<Var> result = new ArrayList<Var>(0);
			return result;
		}
		
	}

	public static class NotEqualConstRightPart extends RightPart{
		Const _const;

		public NotEqualConstRightPart(int line, Const constValue)
		{
			super(line);
			_const = constValue;
		}

		@Override
		public void addBody(GraphCombinatorBody body,
				Collection<String> genericParas, Var leftVar)
				throws EvaluationFailedException
		{
			List<Var> paras = new LinkedList<Var>();
			paras.add(leftVar);
			body.addConnection(NativeSyncFactory.createNotEqual(_const, getLine()), Helper.higherVar2LowerVar(paras));
		}

		@Override
		public Var getConnectionVar(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return null;
		}

		@Override
		public Collection<Var> getVarUsed(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			Collection<Var> result = new ArrayList<Var>(0);
			return result;
		}
		
	}
	
	public static class TestEqualConstValueRefRightPart extends RightPart {
		String _name;

		public TestEqualConstValueRefRightPart(int line, String name)
		{
			super(line);
			_name = name;
		}
		
		private RightPart createActual(Collection<String> genericParas) {
			if (genericParas.contains(_name)) {
				return new TestEqualConstRightPart(getLine(), new ConstRef(getLine(), _name));
			}
			else
				return new TestEqualRightPart(getLine(), new VarPart(new Var(_name, getLine())));
		}

		@Override
		public void addBody(GraphCombinatorBody body,
				Collection<String> genericParas, Var leftVar)
				throws EvaluationFailedException
		{
			createActual(genericParas).addBody(body, genericParas, leftVar);
		}

		@Override
		public Var getConnectionVar(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return createActual(genericParas).getConnectionVar(genericParas);
		}

		@Override
		public Collection<Var> getVarUsed(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return createActual(genericParas).getVarUsed(genericParas);
		}
	}


	public static class NotEqualConstValueRefRightPart extends RightPart {
		String _name;

		public NotEqualConstValueRefRightPart(int line, String name)
		{
			super(line);
			_name = name;
		}
		
		private RightPart createActual(Collection<String> genericParas) {
			if (genericParas.contains(_name)) {
				return new NotEqualConstRightPart(getLine(), new ConstRef(getLine(), _name));
			}
			else
				return new NotEqualRightPart(getLine(), new VarPart(new Var(_name, getLine())));
		}

		@Override
		public void addBody(GraphCombinatorBody body,
				Collection<String> genericParas, Var leftVar)
				throws EvaluationFailedException
		{
			createActual(genericParas).addBody(body, genericParas, leftVar);
		}

		@Override
		public Var getConnectionVar(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return createActual(genericParas).getConnectionVar(genericParas);
		}

		@Override
		public Collection<Var> getVarUsed(Collection<String> genericParas)
				throws EvaluationFailedException
		{
			return createActual(genericParas).getVarUsed(genericParas);
		}
	}

	
	private Part _left;
	private RightPart _right;
	

	@Override
	public void addBody(GraphCombinatorBody body,
			Collection<String> genericParas) throws EvaluationFailedException
	{
		Var leftVar;
		if (_left.getConnectionVar(genericParas) == null) {
			leftVar = Helper.createNewVar(body);
		}
		else
			leftVar = _left.getConnectionVar(genericParas);
		
		_left.addBody(body, genericParas, leftVar);
		_right.addBody(body, genericParas, leftVar);
	}

	@Override
	public Set<Var> getVarUsed(Collection<String> genericParas)
			throws EvaluationFailedException
	{
		Set<Var> result = new HashSet<Var>();
		result.addAll(_left.getVarUsed(genericParas));
		result.addAll(_right.getVarUsed(genericParas));
		return result;
	}

	public SetMemberExpr(int line, Part left, RightPart right)
	{
		super(line);
		_left = left;
		
		_right = right;
	}

}
